package com.blue.base.redis.utils;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.core.RedisOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.SessionCallback;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * redis操作实现类
 *
 * @author liulei
 * @version 1.0
 */
@Component
@ConditionalOnProperty(value = "spring.redis")
public class RedisUtils {

    public static RedisUtils redisUtils;

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    @PostConstruct
    public void initRedisTemplate() {
        redisUtils = this;
        redisTemplate.setValueSerializer(new StringRedisSerializer());
    }

    /**
     * 设置key
     *
     * @param key   键
     * @param value 值
     * @param time  过期时间(秒)
     */
    public static void set(String key, String value, long time) {
        redisUtils.redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
    }

    /**
     * key不存在时，对key的值进行设置，返回true，否则返回false
     *
     * @param key        键
     * @param value      值
     * @param expireTime 过期时间
     * @param unit       过期时间单位
     * @return 操作结果
     */
    public static boolean setNx(String key, Object value, long expireTime, TimeUnit unit) {
        return redisUtils.redisTemplate.execute(new SessionCallback<Boolean>() {
            @Override
            public Boolean execute(RedisOperations operations) throws DataAccessException {
                // watch机制
                operations.multi();
                operations.opsForValue().setIfAbsent(key, value);
                operations.expire(key, expireTime, unit);
                List exec = operations.exec();
                if (exec == null || exec.isEmpty()) {
                    return false;
                }
                return (Boolean) exec.get(0);
            }
        });
    }

    /**
     * 获取key的值
     *
     * @param key 键
     * @return 值
     */
    public static String get(String key) {
        return redisUtils.redisTemplate.opsForValue().get(key);
    }

    /**
     * 删除某个key
     *
     * @param key 键
     * @return 操作结果
     */
    public static Boolean del(String key) {
        return redisUtils.redisTemplate.delete(key);
    }

    /**
     * 删除key集合
     *
     * @param keys 键集合
     * @return 操作结果
     */
    public static Long del(List<String> keys) {
        return redisUtils.redisTemplate.delete(keys);
    }

    /**
     * 设置某个key过期时间
     *
     * @param key  键
     * @param time 过期时间(秒)
     * @return 操作结果
     */
    public static Boolean expire(String key, long time) {
        return redisUtils.redisTemplate.expire(key, time, TimeUnit.SECONDS);
    }

    /**
     * 获取某个key的过期时间
     *
     * @param key 键
     * @return 过期时间(秒)
     */
    public static Long getExpire(String key) {
        return redisUtils.redisTemplate.getExpire(key, TimeUnit.SECONDS);
    }

    /**
     * key是否存在
     *
     * @param key 键
     * @return 操作结果
     */
    public static Boolean hasKey(String key) {
        return redisUtils.redisTemplate.hasKey(key);
    }

    /**
     * key的value自增
     *
     * @param key   键
     * @param delta 步长
     * @return 操作结果
     */
    public static Long incr(String key, long delta) {
        return redisUtils.redisTemplate.opsForValue().increment(key, delta);
    }

    /**
     * key的value自减
     *
     * @param key   键
     * @param delta 步长
     * @return 操作结果
     */
    public static Long decr(String key, long delta) {
        return redisUtils.redisTemplate.opsForValue().increment(key, -delta);
    }

    /**
     * 获取hash键的值
     *
     * @param key     键
     * @param hashKey hash建
     * @return 操作结果
     */
    public static Object hGet(String key, String hashKey) {
        return redisUtils.redisTemplate.opsForHash().get(key, hashKey);
    }

    /**
     * 设置hash键的值
     *
     * @param key     键
     * @param hashKey hash建
     * @param time    过期时间(秒)
     * @return 操作结果
     */
    public static Boolean hSet(String key, String hashKey, Object value, long time) {
        redisUtils.redisTemplate.opsForHash().put(key, hashKey, value);
        return expire(key, time);
    }

    /**
     * 设置hashset的键的值
     *
     * @param key     key
     * @param hashKey hash的key
     * @param value   值
     */
    public static void hSet(String key, String hashKey, Object value) {
        redisUtils.redisTemplate.opsForHash().put(key, hashKey, value);
    }

    /**
     * 获取hash建的所有hashKey值
     *
     * @param key key
     * @return hash所有键值对
     */
    public static Map<Object, Object> hGetAll(String key) {
        return redisUtils.redisTemplate.opsForHash().entries(key);
    }

    /**
     * 获取hashSet建的所有hashKey值
     *
     * @param key  key
     * @param time 过期时间(秒)
     * @return hash所有键值对
     */
    public static Boolean hSetAll(String key, Map<String, Object> map, long time) {
        redisUtils.redisTemplate.opsForHash().putAll(key, map);
        return expire(key, time);
    }

    /**
     * 重置hashKey的值
     *
     * @param key 键
     * @param map 值
     */
    public static void hSetAll(String key, Map<String, ?> map) {
        redisUtils.redisTemplate.opsForHash().putAll(key, map);
    }

    /**
     * hash删除key
     *
     * @param key     key
     * @param hashKey hashKey
     */
    public static void hDel(String key, Object... hashKey) {
        redisUtils.redisTemplate.opsForHash().delete(key, hashKey);
    }


    /**
     * hash表是否存在key的hashKey值
     *
     * @param key     键
     * @param hashKey hashKey
     * @return 操作结果
     */
    public static Boolean hHasKey(String key, String hashKey) {
        return redisUtils.redisTemplate.opsForHash().hasKey(key, hashKey);
    }

    /**
     * hash键值自增
     *
     * @param key     ke
     * @param hashKey hashKey
     * @param delta   步长
     * @return 自增值
     */
    public static Long hIncr(String key, String hashKey, Long delta) {
        return redisUtils.redisTemplate.opsForHash().increment(key, hashKey, delta);
    }

    /**
     * hash自增
     *
     * @param key     键
     * @param hashKey hash的键
     * @param delta   步长
     * @return 自增值
     */
    public static Long hDecr(String key, String hashKey, Long delta) {
        return redisUtils.redisTemplate.opsForHash().increment(key, hashKey, -delta);
    }

    /**
     * 获取hset中key的成员
     *
     * @param key 键
     * @return 成员
     */
    public static Set<String> sMembers(String key) {
        return redisUtils.redisTemplate.opsForSet().members(key);
    }

    /**
     * 往hset中添加数据
     *
     * @param key    键
     * @param time   过期时间(秒)
     * @param values 值集合
     * @return 添加的个数
     */
    public static Long sAdd(String key, long time, String... values) {
        Long count = redisUtils.redisTemplate.opsForSet().add(key, values);
        expire(key, time);
        return count;
    }

    /**
     * 获取hset的大小
     *
     * @param key 键
     * @return 总数
     */
    public static Long sSize(String key) {
        return redisUtils.redisTemplate.opsForSet().size(key);
    }

    /**
     * 删除hset的值
     *
     * @param key    键
     * @param values 集合值
     * @return 删除的个数
     */
    public static Long sRemove(String key, String... values) {
        return redisUtils.redisTemplate.opsForSet().remove(key, values);
    }

    /**
     * 获取集合范围内的数据
     *
     * @param key   键
     * @param start 起始位置
     * @param end   结束位置
     * @return 集合值
     */
    public static List<String> lRange(String key, long start, long end) {
        return redisUtils.redisTemplate.opsForList().range(key, start, end);
    }

    /**
     * 获取集合大小
     *
     * @param key 键
     * @return 总数
     */
    public static Long lSize(String key) {
        return redisUtils.redisTemplate.opsForList().size(key);
    }

    /**
     * 查询集合中的key值
     *
     * @param key   键
     * @param index 索引
     * @return 值
     */
    public static String lIndex(String key, long index) {
        return redisUtils.redisTemplate.opsForList().index(key, index);
    }

    /**
     * 取出队列栈中左部元素
     *
     * @param key 键
     * @return 值
     */
    public static String lPopLeft(String key) {
        return redisUtils.redisTemplate.opsForList().leftPop(key);
    }

    /**
     * 取出队列栈中右部分元素
     *
     * @param key 键
     * @return 值
     */
    public static String lPopRight(String key) {
        return redisUtils.redisTemplate.opsForList().rightPop(key);
    }

    /**
     * 往集合为key中存放值value
     *
     * @param key   键
     * @param value 值
     * @param time  过期时间(秒)
     * @return 添加的个数
     */
    public static Long lPush(String key, String value, long time) {
        Long index = redisUtils.redisTemplate.opsForList().rightPush(key, value);
        expire(key, time);
        return index;
    }

    /**
     * 往集合为key中存放值value
     *
     * @param key    键
     * @param time   过期时间(秒)
     * @param values 值
     * @return 添加的个数
     */
    public static Long lPushAll(String key, Long time, String... values) {
        Long count = redisUtils.redisTemplate.opsForList().rightPushAll(key, values);
        expire(key, time);
        return count;
    }

    /**
     * 删除集合key的键值对
     *
     * @param key   键
     * @param count 个数
     * @param value 值
     * @return 删除的个数
     */
    public static Long lRemove(String key, long count, Object value) {
        return redisUtils.redisTemplate.opsForList().remove(key, count, value);
    }
}
